"use strict";
var PrismToImg = (function(){
	var c = {
		lineHeight: 20,
		width:560,
		margin:'10 10 20',
		color: 'black',
		fontStyle: 'normal',
		fontWeight: 'normal',
		fontSize: '14px',
		fontFamily: 'consolas',
		themeName: 'default',
		theme : {},
		indent: 4,
		backgroundStripe:true,
		lineNum: true,
	};
	var g = {};
	var init = function(text, language, config){

		for (var key in config){
			if(config.hasOwnProperty(key)){
				c[key] = config[key];
			}
		}
		var temMarginArr = c.margin.split(' ');
		c.marginL = parseInt(temMarginArr[0]);
		c.marginT = parseInt(temMarginArr[1]);
		c.marginR = parseInt(temMarginArr[2]);
		c.indentStr = new Array(c.indent + 1).join(' ');
		c.language = language;
		c.grammar = Prism.languages[language];
		c.theme = getParsedTheme(c.themeName);
		text = text.replace(/\t/g,c.indentStr);
		var parsedToken = Prism.util.encode(Prism.tokenize(text, c.grammar, c.language));

		g.canvas = c.canvasElement.getContext('2d');
		g.lineArr = [];
		g.lineArr[1] = 1;
		if(c.lineNum){
			c.font = getFont();
			c.marginL += g.canvas.measureText('555').width;
		}
		c.innerWidth = c.width - c.marginL - c.marginR;
		initGlobal();
		draw(parsedToken);

		c.canvasElement.height = (g.line + 1) * c.lineHeight;
		g.maxLine = g.line;
		initGlobal();
		drawBackground();
		g.canvas.textBaseline = 'bottom';
		draw(parsedToken);
		return this;
	}
	var initGlobal = function(){
		g.line = 1;
		g.lineArrCursor = 1;
		g.classes = [];
		g.charPosition = 0;//相对于innerWidth
		g.lastIndent = '';
	}
	var draw = function(obj) {
		if (Array.isArray(obj)) {
			obj.map(function(element) {
				draw(element);
			});
		}else if(typeof obj == 'string') {
			obj = obj.replace(/&lt;/g, '<').replace(/&amp;/g, '&');
			if(obj.indexOf('\n') >= 0){
				var strLines = obj.split('\n');
				var strLinesLen = strLines.length;
				for(var i = 0; i < strLinesLen - 1; i++){
					if(i > 0){
						var lastIndentMatch = strLines[i].match(/^(\s+)/);
						if(lastIndentMatch){
							g.lastIndent = lastIndentMatch[0];
						}else{
							g.lastIndent = '';
						}
					}
					drawElement(strLines[i]);
					g.line++;
					g.lineArrCursor++;
					g.lineArr[g.lineArrCursor] = 1;
					g.charPosition = 0;
				}
				var lastLine = strLines[strLinesLen - 1];
				if(lastLine){
					var lastLineMatch = lastLine.match(/^(\s+)/);
					if(lastLineMatch){
						g.lastIndent = lastLineMatch[0];
					}else{
						g.lastIndent = '';
					}
				}
				drawElement(lastLine);
			}else{
				drawElement(obj);
			}
		}else if(obj instanceof Prism.Token){
			g.classes.push(obj.type);
			draw(obj.content);
			g.classes.pop(obj.type);
		}
	};
	var drawElement = function(str){
		var classLen = g.classes.length;
		if(classLen > 0){
			if(c.theme.hasOwnProperty(g.classes[classLen - 1])){
				var currentStyle = c.theme[g.classes[classLen - 1]];
				g.canvas.fillStyle = currentStyle.color;
				g.canvas.font = getFont(currentStyle);
			}
		}else{
			g.canvas.fillStyle = c.color;
			g.canvas.font = getFont();
		}
		var temCharPosition = g.charPosition + g.canvas.measureText(str).width;
		if(temCharPosition > c.innerWidth){
			returnAndNewLine(str);
		}else{
			g.canvas.fillText(str, c.marginL + g.charPosition, c.marginT + g.line * c.lineHeight);
			g.charPosition = temCharPosition;
		}
	};
	var drawBackground = function(){
		if(!(typeof c.backgroundColor === 'string')){
			if(typeof c.theme.global.backgroundColor === 'string')
			c.backgroundColor = c.theme.global.backgroundColor;
		}
		if(!(typeof c.backgroundStripeColor === 'string')){
			if(typeof c.theme.global.backgroundStripeColor === 'string')
			c.backgroundStripeColor = c.theme.global.backgroundStripeColor;
		}
		g.canvas.fillStyle = c.backgroundColor;
		g.canvas.fillRect(0, 0, c.width, c.marginT + g.maxLine * c.lineHeight);
		if(c.backgroundStripe === true){
			var lineArrLen = g.lineArr.length;
			for(var i = 1; i < lineArrLen; i++){
				if(i % 2 === 1){
					g.canvas.fillStyle = c.backgroundStripeColor;
					g.canvas.fillRect(
						0,
						c.marginT + (g.line - 1) * c.lineHeight,
						c.width,
						g.lineArr[i] * c.lineHeight
					);
				}
				if(c.lineNum){
					g.canvas.fillStyle = 'black';
					g.canvas.textBaseline = 'bottom';
					g.canvas.font = getFont();
					g.canvas.fillText(i, 0, c.marginT + g.line * c.lineHeight);
				}
				g.line += g.lineArr[i];
			}
			g.line = 1;
		}
	}
	var returnAndNewLine = function(str){
		var strLen = str.length;
		var newStr = '';
		var i;
		for (i = 0; i < strLen; i++){
			newStr = newStr + str.charAt(i);
			if(g.charPosition + g.canvas.measureText(newStr).width > c.innerWidth){
				break;
			}
		}
		newStr = newStr.substr(0, newStr.length - 1);
		if(g.canvas.measureText(g.lastIndent).width > Math.floor((c.innerWidth)/2)){
			getMaxIndent();
		}
		if(g.lastIndent.length % c.indent != 0){
			indentNum = g.lastIndent.length;
			indentNum = Math.ceil(indentNum / c.indent);
			var newIndent = '';
			for(i = 0; i < indentNum; i++){
				newIndent += c.indentStr;
			}
			g.lastIndent = newIndent;
		}
		var restStr = g.lastIndent + str.substr(newStr.length);
		g.canvas.fillText(newStr, c.marginL + g.charPosition, c.marginT + g.line * c.lineHeight);
		g.line++;
		g.lineArr[g.lineArrCursor]++;
		g.charPosition = 0;
		drawElement(restStr);
	};
	var getFont = function(def){
		var resultArray = [c.fontStyle, c.fontWeight, c.fontSize, c.fontFamily];
		if(def){
			var fontAttrArray = ['style', 'weight'];
			for(var i = 0; i < 2; i++){
				if(def.hasOwnProperty(fontAttrArray[i])){
					resultArray[i] = def[fontAttrArray[i]];
				}
			}
		}
		return resultArray.join(' ');
	};
	var getParsedTheme = function(themeName){
		var theme = JSON.parse(PrismToImg.themes[themeName]);
		var parsedTheme = {};
		var i, j, themeLen = theme.length;
		var singleDef, singleDefName, singleDefNameLen, singleDefAttr, attrName,currentDefName;
		for(i = 0; i < themeLen; i++){
			singleDef = theme[i];
			singleDefName = singleDef[0];
			singleDefNameLen = singleDefName.length;
			singleDefAttr = singleDef[1];
			for(j = 0; j < singleDefNameLen; j++){
				currentDefName = singleDefName[j];
				if(!parsedTheme.hasOwnProperty(currentDefName)){
					parsedTheme[currentDefName] = {};
				}
				for(attrName in singleDefAttr){
					if(singleDefAttr.hasOwnProperty(attrName)){
						parsedTheme[currentDefName][attrName] = singleDefAttr[attrName];
					}
				}
			}
		}
		return parsedTheme;
	};
	var getMaxIndent = function(){
		if(typeof g.maxIndent === 'string'){
			g.lastIndent = g.maxIndent;
		}else{
			var newIndent = '';
			while(1){
				newIndent += c.indentStr;
				if(g.canvas.measureText(newIndent).width > Math.floor(c.innerWidth/2)){
					break;
				}
			}
			g.maxIndent = newIndent;
			g.lastIndent = newIndent;
		}
	};
	var getUrl = function(){
		return c.canvasElement.toDataURL('image/png');
	};
	var me = {
		draw : init,
		themes : {},
		url : getUrl,
	};
	return me;
}());


PrismToImg.themes.default = '[[["comment","prolog","doctype","cdata"], {"color": "#708090"}],'+
	'[["punctuation"], {"color": "#999"}],'+
	'[["property","tag","boolean","number","constant","symbol"], {"color": "#905"}],'+
	'[["selector","attr-name","string","builtin"], {"color": "#690"}],'+
	'[["operator","entity","url","variable"], {"color": "#a67f59"}],'+
	'[["atrule","attr-value","keyword"], {"color": "#07a"}],'+
	'[["function"],{"color": "#DD4A68"}],'+
	'[["regex","important"], {"color": "#e90"}],'+
	'[["important"], {"weight": "bold"}],'+
	'[["global"],{"backgroundColor": "#fdfdfd","backgroundStripeColor":"#e2f1f8"}]]';